package redsig.signature;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Collection;

import core.Adapter;



/**
 * @author  Bacher
 */
public class DocumentSigner {
	
	private Signature signature;
	private byte[] sig;
	private Certificate[] certs;
	private PrivateKey privateKey;
	/**
	 * @uml.property  name="signatureFile"
	 * @uml.associationEnd  
	 */
	private redsig.signature.Signature signatureFile;
	
	private final String PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOPXtp59WAymaHiAdTEiGJp0u8++MQaTx6LjtS" +
									 "DXfVFN9YZItpc6NJJg6TxkjvBeSTZtPCGghi9J8mx2bJZqS0Novc16WNwiAWowViKiiyjjX/Ef/I" +
									 "89rvIBzY7bxG9NSlGeCJzTYGYn2+YACHsXm/sI/KoNodidmG7dETxLjxzQIDAQAB";
	
	private final String PRIVATE_KEY="MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM49e2nn1YDKZoeIB1MSIYmnS7z7" +
			"4xBpPHouO1INd9UU31hki2lzo0kmDpPGSO8F5JNm08IaCGL0nybHZslmpLQ2i9zXpY3CIBajBWIq" +
			"KLKONf8R/8jz2u8gHNjtvEb01KUZ4InNNgZifb5gAIexeb+wj8qg2h2J2Ybt0RPEuPHNAgMBAAEC" +
			"gYALvb5P6i3idiNeJeVc2lRkdMzABosHvSX/QrCH3FJtJBIPAzJYn4e1O2BrE0fFq802gw0dKMQ/" +
			"dfO1jnaQkrJfoee/f4OHzumACOSAkZB/K4T6I8Pyhk3JnrwOSkc88SyzypgVuift7Eez4DZVzUIj" +
			"X+6t3YDK6rDAIVHp3sdplQJBAO+q3hNBVsi7sF/mzp5qX1EEFrMch6yEyt5GcZbIN1SkM8gzCCeF" +
			"otuXicMCK036n2kUiJJDYNhdoT/KQfCkt3MCQQDcS3T4vgI/fq6xI9P4Wv1mw9+snytxK3f/2lAg" +
			"BpJgVW2X8oKo7/0j2IpjEZJqf9ZgdBFCfBX++Oy+AsIjCOG/AkEAz0u+K29vTc4xXrG28wRUjzF3" +
			"JNK/cvOkuJ67bsycNwSTmUyyd+S5mS+4Q0ikBh2JNg1BlyjaIirR5ufdIvSFiwJABrIkdAsSdmub" +
			"U7cLEllxqlX5zn1oDKCNnTE9jjuk51ixZBTy87+XqidCzZATKzmHgpcEj0jGQmG+kGf1DquOcQJB" +
			"AOdnftD4mKoQTvakVT9YfQEiB4TnAjxoQVxa7GBfcm3qvH7DaIMhXpsHEE+O8bjqUxMgGciCgnhF" +
			"u9RqPkjZWHE=";
	public DocumentSigner(){
		try {
			signature = Signature.getInstance("SHA1withRSA");
			
			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @return
	 * @uml.property  name="sig"
	 */
	public byte[] getSig() {
		return sig;
	}
	
	public void processKey(File file){
		InputStream fl = readFile(file);
	    byte[] key;
		try {
	         key = new byte[fl.available()];
	         KeyFactory kf = KeyFactory.getInstance("RSA");
	         fl.read ( key, 0, fl.available() );
	         fl.close();
	         PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
	         privateKey = kf.generatePrivate(keysp);
	         //Adapter.setPrivateKey(kf.generatePrivate(keysp));
	        // System.out.println(Adapter.getPrivateKey());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
	}
	
	private InputStream readFile(File file){
        FileInputStream fis;
		try {
			fis = new FileInputStream(file);
			DataInputStream dis = new DataInputStream(fis);
			byte[] bytes = new byte[dis.available()];
			dis.readFully(bytes);
			ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
			return bais;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;

	}
	
	public void processCertificate(File file){
		CertificateFactory cf;
		try {
			cf = CertificateFactory.getInstance("X.509");
	        InputStream certstream = readFile(file);
	        
	        Collection c = cf.generateCertificates(certstream) ;
	        certs = new Certificate[c.toArray().length];

	        if (c.size() == 1) {
	            certstream = readFile(file);
//	            System.out.println("One certificate, no chain.");
	            Certificate cert = (Certificate) cf.generateCertificate(certstream) ;
//	            System.out.println(cert.getPublicKey());
	            Adapter.setCertificate(cert);
	            certs[0] = cert;
	        } else {
//	            System.out.println("Certificate chain length: "+c.size());
	            certs = (Certificate[])c.toArray();    
	        } 
	        //Adapter.setCertificate(certs);
	        /*if(Adapter.getSignature() != null)
	            	SignatureImpl.verifySignature(Adapter.getMap().get(Adapter.getTreeBuilder().getRoot()), Adapter.getSignature());*/
		} catch (CertificateException e) {
			e.printStackTrace();
		}
	}
	
	public void sign(byte[] hash){
		try {
			/*
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(Adapter.base64ToByte(PRIVATE_KEY));
			PrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);
			*/
			signature.initSign(privateKey);
			signature.update(hash);
			sig = signature.sign();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	public boolean verify(byte[] sig){
		try {
			/*
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(Adapter.base64ToByte(PUBLIC_KEY));
			PublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);
			*/
			signature.initVerify(certs[0].getPublicKey());
			signature.update(sig);
//			System.out.println("Document-signature: " + Adapter.byteToBase64(sig));
//			System.out.println("Signature-File: " + signatureFile.getSignature());
			return signature.verify(signatureFile.getSignature());
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * @param signatureFile
	 * @uml.property  name="signatureFile"
	 */
	public void setSignatureFile(redsig.signature.Signature signatureFile) {
		this.signatureFile = signatureFile;
	}

	/**
	 * @return
	 * @uml.property  name="signatureFile"
	 */
	public redsig.signature.Signature getSignatureFile() {
		return signatureFile;
	}
	
}
